<%@ Page Language="C#" %>
<%@ Import namespace="SubSonic.Utilities"%>
<%@ Import Namespace="SubSonic" %>
<%
    //The data we need
    string providerName = "#PROVIDER#";
    string tableName = "#TABLE#";
    TableSchema.Table tbl = DataService.GetSchema(tableName, providerName, TableType.Table);
    DataProvider provider = DataService.Providers[providerName];
    LanguageType lang = LanguageType.CSharp;

    TableSchema.TableColumnCollection cols = tbl.Columns;
    string className = tbl.ClassName;
	string thisPK = tbl.PrimaryKey.PropertyName;
	string varPK = tbl.PrimaryKey.ArgumentName;
	string varPKType = Utility.GetVariableType(tbl.PrimaryKey.DataType, tbl.PrimaryKey.IsNullable, lang);
%>
//Generated on <%=DateTime.Now.ToString() %> by <%=Environment.UserName %>
namespace <%=provider.GeneratedNamespace %>{



    /// <summary>
    /// This is an ActiveRecord class which wraps the <%=tableName%> table.
    /// </summary>
    [Serializable]
    public partial class <%=className%> : ActiveRecord[<]<%= className%>[>]
    {
    
	    #region Default Settings
        /// <summary>
        /// Retrieve the schema for this table
        /// </summary>	   
	    protected static void SetSQLProps() 
	    {
		    GetTableSchema();
	    }
	    #endregion

        #region Schema Accessor
        /// <summary>
        /// Gets the schema that describes the persistance of this object
        /// </summary>    
	    public static TableSchema.Table Schema
        {
            get
            {
                if (BaseSchema == null)
                {
                    SetSQLProps();
                }
                return BaseSchema;
            }
        }
    	
        private static void GetTableSchema() 
	    {
            if(!IsSchemaInitialized)
            {
                //Schema declaration

				TableSchema.Table schema = new TableSchema.Table("<%=tableName%>", TableType.Table, DataService.Provider);
                schema.Columns = new TableSchema.TableColumnCollection();
                schema.SchemaName = "<%=tbl.SchemaName%>";

                //columns
                <%
                foreach(TableSchema.TableColumn col in cols)
                {
                    string varName = "col" + col.ArgumentName;
                %>
                TableSchema.TableColumn <%=varName %> = new TableSchema.TableColumn(schema);
                <%=varName %>.ColumnName = "<%=col.ColumnName%>";
                <%=varName %>.DataType = DbType.<%=col.DataType %>;
                <%=varName %>.MaxLength = <%=col.MaxLength %>;
                <%=varName %>.AutoIncrement = <%=col.AutoIncrement.ToString().ToLower() %>;
                <%=varName %>.IsNullable = <%=col.IsNullable.ToString().ToLower()%>;
                <%=varName %>.IsPrimaryKey = <%=col.IsPrimaryKey.ToString().ToLower()%>;
                <%=varName %>.IsForeignKey = <%=col.IsForeignKey.ToString().ToLower()%>;
                <%=varName %>.IsReadOnly = <%= col.IsReadOnly.ToString().ToLower() %>;
                <% if (!String.IsNullOrEmpty(col.DefaultSetting))
				   {					   
				%>
						<%=varName%>.DefaultSetting = @"<%= col.DefaultSetting%>";
				<%
					}
                %>

                <%
				if(col.IsForeignKey)
				{
                %>
				<%=varName %>.ForeignKeyTableName = "<%= col.ForeignKeyTableName %>";
                <% } %>
                schema.Columns.Add(<%=varName%>);

                <%
                }
                %>
                BaseSchema = schema;

                //add this schema to the provider
                //so we can query it later
                DataService.Provider.AddSchema("<%=tableName%>",schema);
            }
        }
        #endregion
        
        #region Query Accessor
        /// <summary>
        /// Generates a new query based on the schema of this object
        /// </summary>        
	    public static Query CreateQuery()
	    {
		    return new Query(Schema);
	    }
	    #endregion
	    
	    #region .ctors
        /// <summary>
        /// default constructor
        /// </summary>		    
	    public <%=className %>()
	    {
            SetSQLProps();
            SetDefaults();

            MarkNew();
        }

        /// <summary>
        /// loads a new object with the given key
        /// </summary>
	    public <%=className %>(object keyID)
	    {
		    SetSQLProps();
            SetDefaults();
		    LoadByKey(keyID);
	    }
    	 
        /// <summary>
        /// loads a new object with the given value in the given field
        /// </summary>
	    public <%=className %>(string columnName, object columnValue)
        {
            SetSQLProps();
            SetDefaults();
            LoadByParam(columnName,columnValue);
        }
        
	    #endregion
	    
	    #region Props
	    
        <%
        foreach(TableSchema.TableColumn col in cols){
            string propName = col.PropertyName;
            string varType = Utility.GetVariableType(col.DataType, col.IsNullable, lang);
        %>  
        /// <summary>
        /// Gets and Sets the value for <%= propName %>
        /// </summary>        
        [XmlAttribute("<%=propName%>")]
        public <%=varType%> <%=propName%> 
	    {
		    get { return GetColumnValue[<]<%= varType%>[>]("<%= col.ColumnName %>"); }
            set 
		    {
			    MarkDirty();
			    SetColumnValue("<%=col.ColumnName %>", value);
            }
        }
	    <%
	    }
	    %>
	    #endregion
	    
	    <%if (tbl.PrimaryKeyTables.Count > 0)
{%>
	    #region PrimaryKey Methods
	    <%
    TableSchema.PrimaryKeyTableCollection pkTables = tbl.PrimaryKeyTables;
	if (pkTables != null)
	{
		ArrayList usedMethodNames = new ArrayList();
		foreach (TableSchema.PrimaryKeyTable pk in pkTables)
		{
			TableSchema.Table pkTbl = DataService.GetSchema(pk.TableName, providerName, TableType.Table);
			if (pkTbl.PrimaryKey != null)
			{
				string pkClass = pk.ClassName;
				string pkClassQualified = provider.GeneratedNamespace + "." + pkClass;
				string pkMethod = pk.ClassNamePlural;
				string pkColumn = pk.PropertyName;

				if (Utility.IsMatch(pkClass, pkMethod))
				{
					pkMethod += "Records";
				}

				if (pk.ClassName == className)
				{
					pkMethod = "Child" + pkMethod;
				}

				if (usedMethodNames.Contains(pkMethod))
				{
					pkMethod += "From" + className;
					if (usedMethodNames.Contains(pkMethod))
					{
						pkMethod += pkColumn;
					}
				}

				usedMethodNames.Add(pkMethod);
				
				if(!String.IsNullOrEmpty(provider.RelatedTableLoadPrefix))
				{
					pkMethod = provider.RelatedTableLoadPrefix + pkMethod;
				}

				bool methodsNoLazyLoad = !provider.GenerateRelatedTablesAsProperties && !provider.GenerateLazyLoads;
				bool methodsLazyLoad = !provider.GenerateRelatedTablesAsProperties && provider.GenerateLazyLoads;
				bool propertiesNoLazyLoad = provider.GenerateRelatedTablesAsProperties && !provider.GenerateLazyLoads;
				bool propertiesLazyLoad = provider.GenerateRelatedTablesAsProperties && provider.GenerateLazyLoads;

                %>
                /// <summary>
                /// Gets the foreign key objects tied to this instance
                /// </summary>
                <%
                
				if (methodsNoLazyLoad)
				{
%>
		public <%= pkClassQualified %>Collection <%=pkMethod%>()
		{
			return new <%=pkClassQualified%>Collection().Where(<%=pkTbl.ClassName%>.Columns.<%=pkColumn%>, <%=tbl.PrimaryKey.PropertyName%>).Load();
		}
<%
			}
			else if (methodsLazyLoad)
			{
%>
		public <%= pkClassQualified %>Collection <%=pkMethod%>()
		{
			if(col<%=pkMethod%> == null)
			{
				col<%=pkMethod%> = new <%= pkClassQualified %>Collection().Where(<%=pkTbl.ClassName%>.Columns.<%=pkColumn%>, <%=tbl.PrimaryKey.PropertyName%>).Load();
			}
			return col<%=pkMethod%>;
		}
		private <%= pkClassQualified %>Collection col<%=pkMethod%>;
		
<%
			}
			else if (propertiesNoLazyLoad)
			{
%>
		public <%= pkClassQualified %>Collection <%=pkMethod%>
		{
			get
			{
				return new <%= pkClassQualified %>Collection().Where(<%=pkTbl.ClassName%>.Columns.<%=pkColumn%>, <%=tbl.PrimaryKey.PropertyName%>).Load();
			}
		}
<%
			}
			else if (propertiesLazyLoad)
			{
%>		
		public <%= pkClassQualified %>Collection <%=pkMethod%>
		{
			get
			{
				if(col<%=pkMethod%> == null)
				{
					col<%=pkMethod%> = new <%= pkClassQualified %>Collection().Where(<%=pkTbl.ClassName%>.Columns.<%=pkColumn%>, <%=tbl.PrimaryKey.PropertyName%>).Load();
				}
				return col<%=pkMethod%>;			
			}
		}
		private <%= pkClassQualified %>Collection col<%=pkMethod%>;
		<%
			}
		}
	}
}
%>
		#endregion
		<%   
	}
%>

	 	
			
	    <%if (tbl.ForeignKeys.Count > 0) { %>
	    
	    
	    #region ForeignKey Properties
	    <%
            TableSchema.ForeignKeyTableCollection fkTables = tbl.ForeignKeys;
			
            if (fkTables != null) {
				ArrayList usedPropertyNames = new ArrayList();
                foreach (TableSchema.ForeignKeyTable fk in fkTables) 
				{
                    TableSchema.Table fkTbl = DataService.GetSchema(fk.TableName, providerName, TableType.Table);
                    string fkClass = fk.ClassName;
					string fkClassQualified = provider.GeneratedNamespace + "." + fkClass;
                    string fkMethod = fk.ClassName;
                    string fkID = fk.PropertyName;
                    
					
                    //it's possible this table is "relatin to itself"
                    //check to make sure the class names are not the same
                    //if they are, use the fk columnName
					if (fk.ClassName == className)
					{
					    fkMethod = "Parent" + fk.ClassName;
					}

					if (usedPropertyNames.Contains(fk.ClassName))
					{
						fkMethod += "To" + fkID;
					}
					
					if(tbl.GetColumn(fkMethod) != null)
					{
						fkMethod += "Record";
					}
%>
        /// <summary>
        /// Returns a <%=fkClass%> ActiveRecord object related to this <%=className%>
        /// </summary>
	    public <%=fkClassQualified%> <%=fkMethod%>
        {
	        get { return <%=fkClassQualified%>.FetchByID(this.<%=fkID%>); }
	        set
	        {
		        MarkDirty();
		        SetColumnValue("<%=fkID%>", value.<%=fkTbl.PrimaryKey.PropertyName%>);
	        }
        }
	    
	    <%
			usedPropertyNames.Add(fk.ClassName);
            }
        }
	    %>
	    #endregion
	    <%} else {%>
	    //no foreign key tables defined (<%=tbl.ForeignKeys.Count.ToString() %>)
	    <%} %>
	    
	    <%if (tbl.ManyToManys.Count > 0) { %>
	    #region Many To Many Helpers
	    <%
			TableSchema.ManyToManyRelationshipCollection mm = tbl.ManyToManys;
			if (mm != null)
			{
				ArrayList usedConstraints = new ArrayList();
				foreach (TableSchema.ManyToManyRelationship m in mm)
				{
					if (!usedConstraints.Contains(m.ForeignTableClassName))
					{
						usedConstraints.Add(m.ForeignTableClassName);
						string fkClass = m.ForeignTableClassName;
						string fkClassQualified = provider.GeneratedNamespace + "." + fkClass;
                
	    %>
        /// <summary>
        /// Returns a <%=fkClass%> ActiveRecord object related to this <%=className%>
        /// </summary>	     
        public <%=fkClassQualified%>Collection Get<%=fkClass%>Collection() {

            return <%=className%>.Get<%=fkClass%>Collection(this.<%=thisPK%>);

        }
        /// <summary>
        /// Returns a <%=fkClass%> ActiveRecord object related to the given object
        /// </summary>	     
        public static <%=fkClassQualified%>Collection Get<%=fkClass%>Collection(<%= varPKType%> <%= varPK%>) {

            SubSonic.QueryCommand cmd = new SubSonic.QueryCommand(
                "SELECT * FROM <%=m.ForeignTableName%> INNER JOIN <%=m.MapTableName%> ON "+
                "<%=m.ForeignTableName%>.<%=m.ForeignPrimaryKey%>=<%=m.MapTableName%>.<%=m.MapTableForeignTableKeyColumn%> WHERE <%=m.MapTableName%>.<%=m.MapTableLocalTableKeyColumn%>=@<%=m.MapTableLocalTableKeyColumn%>", <%=className%>.Schema.Provider.Name);
            
            cmd.AddParameter("@<%=m.MapTableLocalTableKeyColumn%>", <%= varPK%>);
            
            IDataReader rdr = SubSonic.DataService.GetReader(cmd);
            <%=fkClass%>Collection coll = new <%=fkClass%>Collection();
            coll.LoadAndCloseReader(rdr);

            return coll;

        }
        /// <summary>
        /// Saves the given items as a relationship to the PK item
        /// </summary>	     
        public static void Save<%=fkClass%>Map(<%= varPKType%> <%= varPK%>, <%=fkClass%>Collection items) {
            
            QueryCommandCollection coll = new SubSonic.QueryCommandCollection();

            //delete out the existing
            QueryCommand cmdDel = new QueryCommand("DELETE FROM <%=m.MapTableName%> WHERE <%=m.MapTableLocalTableKeyColumn%>=@<%=m.MapTableLocalTableKeyColumn%>", <%=className%>.Schema.Provider.Name);
            cmdDel.AddParameter("@<%=m.MapTableLocalTableKeyColumn%>", <%= varPK%>);
            //add this in
            coll.Add(cmdDel);
			DataService.ExecuteTransaction(coll);

            foreach (<%=fkClass%> item in items)
            {
				<%=m.ClassName%> var<%=m.ClassName%> = new <%= m.ClassName%>();
				var<%=m.ClassName%>.SetColumnValue("<%=m.MapTableLocalTableKeyColumn%>", <%= varPK%>);
				var<%=m.ClassName%>.SetColumnValue("<%=m.MapTableForeignTableKeyColumn%>", item.GetPrimaryKeyValue());
				var<%=m.ClassName%>.Save();
            }
        }

        /// <summary>
        /// Saves the given items as a relationship to the PK item
        /// </summary>	     
        public static void Save<%=fkClass%>Map(<%= varPKType%> <%= varPK%> , <%= varPKType%>[] itemList) 
        {
            QueryCommandCollection coll = new SubSonic.QueryCommandCollection();

            //delete out the existing
             QueryCommand cmdDel = new QueryCommand("DELETE FROM <%=m.MapTableName%> WHERE <%=m.MapTableLocalTableKeyColumn%>=@<%=m.MapTableLocalTableKeyColumn%>", <%=className%>.Schema.Provider.Name);
            cmdDel.AddParameter("@<%=m.MapTableLocalTableKeyColumn%>", <%= varPK%>);

            //add this in
            coll.Add(cmdDel);
			DataService.ExecuteTransaction(coll);

            foreach (<%= varPKType%> item in itemList) 
            {
            	<%=m.ClassName%> var<%=m.ClassName%> = new <%= m.ClassName%>();
				var<%=m.ClassName%>.SetColumnValue("<%=m.MapTableLocalTableKeyColumn%>", <%= varPK%>);
				var<%=m.ClassName%>.SetColumnValue("<%=m.MapTableForeignTableKeyColumn%>", item);
				var<%=m.ClassName%>.Save();
            }
        }
        
        /// <summary>
        /// Removes the given relationships
        /// </summary>	     
        public static void Delete<%=fkClass%>Map(<%= varPKType%> <%= varPK%>) 
        {
            QueryCommand cmdDel = new QueryCommand("DELETE FROM <%=m.MapTableName%> WHERE <%=m.MapTableLocalTableKeyColumn%>=@<%=m.MapTableLocalTableKeyColumn%>", <%=className%>.Schema.Provider.Name);
            cmdDel.AddParameter("@<%=m.MapTableLocalTableKeyColumn%>", <%= varPK%>);
            DataService.ExecuteQuery(cmdDel);
		}

	    <%
			}
		}
	}
	    %>
	    #endregion
	    <%} else {%>
	    //no ManyToMany tables defined (<%=tbl.ManyToManys.Count.ToString() %>)
	    <%} %>

	    #region ObjectDataSource support
    	<%
            string insertArgs = string.Empty;
            string updateArgs = string.Empty;
			string seperator = ",";

			foreach (TableSchema.TableColumn col in cols)
			{
				string propName = col.ArgumentName;
				string varType = Utility.GetVariableType(col.DataType, col.IsNullable, lang);
				
				updateArgs += varType + " " + propName + seperator;
				if (!col.AutoIncrement)
				{
					insertArgs += varType + " " + propName + seperator;
				}
			}
			if (insertArgs.Length > 0)
				insertArgs = insertArgs.Remove(insertArgs.Length - seperator.Length, seperator.Length);
 			if (updateArgs.Length > 0)
				updateArgs = updateArgs.Remove(updateArgs.Length - seperator.Length, seperator.Length);
    	%>
    	
	    /// <summary>
	    /// Inserts a record, can be used with the Object Data Source
	    /// </summary>
	    public static void Insert(<%=insertArgs%>)
	    {
		    <%=className %> item = new <%=className %>();
		    <% 
		    foreach (TableSchema.TableColumn col in cols) {
                if (!col.AutoIncrement) { 
            %>
            item.<%=col.PropertyName%> = <%=col.ArgumentName%>;
            <%
                }
              } 
            %>
	    
			    item.Save(System.Threading.Thread.CurrentPrincipal.Identity.Name);
	    }

    	
	    /// <summary>
	    /// Updates a record, can be used with the Object Data Source
	    /// </summary>
	    public static void Update(<%=updateArgs%>)
	    {
		    <%=className %> item = new <%=className %>();
		    <% 
		    foreach (TableSchema.TableColumn col in cols) 
			{
				%>
                item.<%=col.PropertyName%> = <%=col.ArgumentName%>;
				<%
			} 
            %>
		    item.IsNew = false;
			    item.Save(System.Threading.Thread.CurrentPrincipal.Identity.Name);
	    }

	    #endregion

	    #region Columns Struct
	    
        /// <summary>
        /// List of columns/properties available in this object
        /// </summary>	
	    public struct Columns
	    {
		    
		    <% 
		    foreach (TableSchema.TableColumn col in cols) {
                string propName = col.PropertyName;
            %>
            /// <summary>
            /// <%= propName %>
            /// </summary>            
            public static string <%=propName%> = @"<%=col.ColumnName%>";
            <%
              } 
            %>

	    }
	    #endregion
    }

    #region <%= className %>Collection
    /// <summary>
    /// Strongly-typed collection for the <%=className%> class.
    /// </summary>

    [Serializable]
    public partial class <%=className%>Collection : ActiveList[<]<%= className%>[>] 
    {
        List[<]Where[>] wheres = new List[<]Where[>]();
        List[<]BetweenAnd[>] betweens = new List[<]BetweenAnd[>]();
        SubSonic.OrderBy orderBy;
    	
        /// <summary>
        /// returns this collection ordered ascending by the given column
        /// </summary>    	
        public <%=className%>Collection OrderByAsc(string columnName) 
	    {
            this.orderBy = SubSonic.OrderBy.Asc(columnName);
            return this;
        }
    	
        /// <summary>
        /// returns this collection ordered descending by the given column
        /// </summary>
        public <%=className%>Collection OrderByDesc(string columnName) 
	    {
            this.orderBy = SubSonic.OrderBy.Desc(columnName);
            return this;
        }

        /// <summary>
        /// returns this collection constrained to dates in the given column between the given values
        /// </summary>
	    public <%=className%>Collection WhereDatesBetween(string columnName, DateTime dateStart, DateTime dateEnd) 
	    {
            return BetweenAnd(columnName, dateStart, dateEnd);
        }

        /// <summary>
        /// append the given where clause to contrain this collection
        /// </summary>
        public <%=className%>Collection Where(Where where) 
	    {
            wheres.Add(where);
            return this;
        }
    	
        /// <summary>
        /// returns this collection with the given field/value pair added to the where clause 
        /// </summary>
        public <%=className%>Collection Where(string columnName, object value) 
	    {
		    if(value != DBNull.Value && value != null)
		    {	
			    return Where(columnName, Comparison.Equals, value);
		    }
		    else
		    {
			    return Where(columnName, Comparison.Is, DBNull.Value);
		    }
        }
    	
        /// <summary>
        /// returns this collection with the given field/value pair added to the where clause 
        /// </summary>
        public <%=className%>Collection Where(string columnName, Comparison comp, object value) 
	    {
            Where where = new Where();
            where.ColumnName = columnName;
            where.Comparison = comp;
            where.ParameterValue = value;
            Where(where);
            return this;
        }
    	
        /// <summary>
        /// returns this collection constrained to dates in the given column between the given values
        /// </summary>
        public <%=className%>Collection BetweenAnd(string columnName, DateTime dateStart, DateTime dateEnd) 
	    {
            BetweenAnd between = new BetweenAnd();
            between.ColumnName = columnName;
            between.StartDate = dateStart;
            between.EndDate = dateEnd;
            between.StartParameterName = "start" + columnName; 
            between.EndParameterName = "end" + columnName; 
            betweens.Add(between);
            return this;
        }
    	
        /// <summary>
        /// loads data from the data store based on the where clause and order previously loaded into this object
        /// </summary>
        public <%=className%>Collection Load() 
        {
            Query qry = new Query(<%=className%>.Schema);
            CheckLogicalDelete(qry);
            foreach (Where where in wheres) 
            {
                qry.AddWhere(where);
            }
             
            foreach (BetweenAnd between in betweens)
            {
                qry.AddBetweenAnd(between);
            }

            if (orderBy != null)
            {
                qry.OrderBy = orderBy;
            }

            IDataReader rdr = qry.ExecuteReader();
            this.Load(rdr);
            rdr.Close();
            return this;
        }
        
        /// <summary>
        /// default constructor
        /// </summary>
        public <%=className%>Collection() 
	    {
        }
    }
    
    #endregion

    
    
}
